from typing import Optional, Dict, List
import pandas as pd
from PySide6.QtCore import QObject, Signal, QTimer
from loguru import logger
from ui.workers import SlowProcessWorker
from ..models.index_data_model import IndexDataModel


class IndexDataController(QObject):
    
    data_loaded = Signal(list)
    ratio_data_loaded = Signal(str, object)  # chart_name, data
    cumulative_return_loaded = Signal(str, dict, dict)  # chart_name, indices, index_data
    volume_ratio_loaded = Signal(dict, dict)  # indices, index_data
    loading_state_changed = Signal(bool)  # is_loading
    
    def __init__(self):
        super().__init__()
        self.model = IndexDataModel()
        self.worker = None
        self.refresh_timer = QTimer()
        self.refresh_timer.timeout.connect(self.load_table_data)
        
    def start_auto_refresh(self, interval_ms: int = 10000):
        self.refresh_timer.start(interval_ms)
        
    def stop_auto_refresh(self):
        if self.refresh_timer.isActive():
            self.refresh_timer.stop()
            
    def load_table_data(self, days_limit: int = 250):
        if self.worker and self.worker.isRunning():
            logger.info("已有 worker 在运行，跳过本次操作")
            return
            
        try:
            slow_tasks = {
                lambda: self.model.get_table_data(days_limit=days_limit): self._on_table_data_loaded
            }
            
            self.worker = SlowProcessWorker(slow_tasks)
            self.worker.start()
            
        except Exception as e:
            logger.exception(f"启动指数数据加载时出错: {e}")
            
    def _on_table_data_loaded(self, table_data):
        try:
            if table_data:
                self.data_loaded.emit(table_data)
                logger.info(f"成功加载 {len(table_data)} 个指数数据")
            else:
                logger.warning("未获取到指数数据")
        except Exception as e:
            logger.exception(f"更新指数数据时出错: {e}")
    
    def load_chart_data(self, start_date: str, end_date: str):
        self.loading_state_changed.emit(True)
        
        try:
            index_pairs = self.model.get_index_pairs()
            cumulative_indices = self.model.get_cumulative_indices()
            volume_ratio_indices = self.model.get_volume_ratio_indices()
            style_indices = self.model.get_style_indices()
            asset_class_indices = self.model.get_asset_class_indices()
            sector_indices = self.model.get_sector_indices()
            
            all_codes = set()
            for pair in index_pairs.values():
                all_codes.update(pair["codes"])
            all_codes.update(cumulative_indices.keys())
            all_codes.update(volume_ratio_indices.keys())
            all_codes.update(style_indices.keys())
            all_codes.update(asset_class_indices.keys())
            all_codes.update(sector_indices.keys())
            
            index_data = self.model.get_index_history_data(list(all_codes), start_date, end_date)
            
            self._process_ratio_charts(index_pairs, index_data)
            
            self.cumulative_return_loaded.emit("main", cumulative_indices, index_data)
            self.volume_ratio_loaded.emit(volume_ratio_indices, index_data)
            self.cumulative_return_loaded.emit("style", style_indices, index_data)
            self.cumulative_return_loaded.emit("asset_class", asset_class_indices, index_data)
            self.cumulative_return_loaded.emit("sector", sector_indices, index_data)
            
        except Exception as e:
            logger.exception(f"获取大小比价数据时出错: {e}")
        finally:
            self.loading_state_changed.emit(False)
    
    def _process_ratio_charts(self, index_pairs: Dict, index_data: Dict):
        for pair_name, pair_info in index_pairs.items():
            code1, code2 = pair_info["codes"]
            df1 = index_data.get(code1)
            df2 = index_data.get(code2)
            
            if df1 is not None and df2 is not None:
                ratio_df = self.model.calculate_ratio(df1, df2)
                if not ratio_df.empty:
                    chart_data = {
                        'x': ratio_df['date'].tolist(),
                        'y': ratio_df['size_ratio'].tolist(),
                        'name': pair_info["name"]
                    }
                    self.ratio_data_loaded.emit(pair_name, chart_data)
                    logger.info(f"成功加载 {pair_info['name']} 比价数据，共 {len(ratio_df)} 条记录")
                else:
                    logger.warning(f"未能计算 {pair_info['name']} 比价数据")
            else:
                logger.warning(f"缺少 {pair_info['name']} 的数据，无法计算比价")
    
    def get_default_date_range(self):
        return self.model.get_default_date_range()
    
    def cleanup(self):
        self.stop_auto_refresh()
        if self.worker and self.worker.isRunning():
            self.worker.shutdown()